package com.rtsapp.server.module;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import com.rtsapp.server.benchmark.script.ScriptRecord;
import com.rtsapp.server.common.IObjectContainer;
import com.rtsapp.server.common.Timer;
import com.rtsapp.server.logger.LoggerFactory;
import com.rtsapp.server.logger.format.DateFormat;
import com.rtsapp.server.monitor.MonitorThread;
import com.rtsapp.server.logger.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 * 应用程序
 * @author admin
 *
 */
public class Application extends AbstractModule implements IObjectContainer {

	private static Logger LOGGER =com.rtsapp.server.logger.LoggerFactory.getLogger( Application.class );

	private final ClassLoader classLoader;
	private SpringObjectContainer  objectContainer ;
	private List<Module> moduleList;

	public Application( String cfgFile ){
		this.setName( cfgFile );
		this.classLoader = Thread.currentThread().getContextClassLoader( );
		this.moduleList =  new ArrayList<Module>( );
		objectContainer = new SpringObjectContainer( cfgFile );

	}


	public void addModule( Module module ){
		this.moduleList.add( module );
	}

	public void removeModule( Module module ){
		this.moduleList.remove(module);
	}


	public Module getModule( String moduleName ){

		for( Module module : this.moduleList ){
			if( module.getName().equals( moduleName ) ){
				return module;
			}
		}

		return null;
	}


	public <T> T getModule( Class<T> claz ){

		for( Module module : this.moduleList ){

			if( claz.isAssignableFrom(module.getClass()) ){
				return (T)module;
			}

		}

		return null;
	}


	public void startApplication( ){

		LOGGER.info("Application initialize");
		if( ! this.initialize( null ) ){
			LOGGER.error("Application initialize fail, System exit" );
			exit(1);
		}

		LOGGER.info("Application start");
		if( ! this.start() ){
			LOGGER.error("Application start fail, System exit" );
			exit(1);
		}

		LOGGER.info( "Application startApplication success" );
	}

	private void exit( int status ){
		LoggerFactory.shutdown();
		System.exit( status );
	}


	@Override
	public boolean initialize(Module parentModule ) {


		// 加载所有对象
		if( ! objectContainer.loadObjects( ) ){
			LOGGER.error("loadObjects error");
			return false;
		}


		// 抽取模块, 将模块放入列表
		AppCfg cfg = objectContainer.getObject( AppCfg.class );
		if( cfg != null ){
			for( String moduleName : cfg.getModuleNames() ){
				Module module = (Module)objectContainer.getObject( moduleName );
				if (module == null) {
					LOGGER.error("Module {} is NULL",moduleName);
					continue;
				}
				module.setName( moduleName );
				addModule( module );
			}
		}

		// 初始化所有 modules
		for( int i = 0; i < moduleList.size(); i++ ){

			Module module = moduleList.get( i );

			if( ! module.initialize( this ) ){
				return false;
			}
		}


		return true;
	}


	@Override
	public boolean start() {

		for( int i = 0; i < moduleList.size(); i++ ){



			String moduleName = null ;
			try {
				Module module = moduleList.get( i );
				moduleName = module.getName();

				if (!module.start()) {
					return false;
				}
			}catch( Throwable ex ){
				LOGGER.error( "第" + i + "个模块:" + moduleName + "启动失败...", ex );
				return false;
			}

		}

		return true;
	}


	@Override
	public void stop() {

		LOGGER.info( "服务器开始关闭.." );

		LOGGER.info( "ScriptRecord关闭" );
		ScriptRecord.getInstance().stop();
		LOGGER.info("ScriptRecord关闭成功");


		LOGGER.info("Timer开始关闭");
		Timer.getInstance().stop();
		LOGGER.info("Timer关闭成功");

		LOGGER.info("MonitorThread关闭");
		MonitorThread.stop();
		LOGGER.info( "MonitorThread关闭成功" );

		for( int i = moduleList.size() - 1 ; i >= 0; i-- ){
			String moduleName = moduleList.get( i ).getName();

			try {
				LOGGER.error( "第" + i + "个模块:" +  moduleName + "开始关闭");
				moduleList.get(i).stop();
				LOGGER.error("第" + i + "个模块:" + moduleName  + "关闭成功"  );
			}catch( Throwable ex ){
				LOGGER.error( "第" + i + "个模块:" + moduleName + "关闭失败...", ex );
			}
		}

		LOGGER.info("DateFormat开始关闭");
		DateFormat.stop();
		LOGGER.info("DateFormat关闭成功");

		LOGGER.info( "服务器已经关闭.." );

		LoggerFactory.shutdown();
	}

	@Override
	public void destroy() {

		for( int i = moduleList.size() - 1 ; i >= 0; i-- ){
			moduleList.get( i ).destroy( );
		}

		exit(0);
	}


	@Override
	public Object getObject(String name) {
		try {
			return objectContainer.getObject(name);
		}catch( Throwable ex ){
			LOGGER.error( "getObject(" + name + ") 异常", ex );
			return null;
		}
	}


	@Override
	public <T> T getObject(Class<T> requiredType) {
		try {

			return objectContainer.getObject(requiredType);
		}catch( Throwable ex ){
			LOGGER.error( "getObject(" + requiredType + ") 异常", ex );
			return null;
		}
	}



	/**
	 * 内部Spring对象容器
	 * @author dengyingtuo
	 *
	 */
	private static class SpringObjectContainer implements IObjectContainer{

		private ApplicationContext ctx = null;
		private String cfgFile = null;

		public SpringObjectContainer( String cfgFile ){
			this.cfgFile = cfgFile;
		}

		public boolean loadObjects(){
			if( ctx == null ){
				try {
					ctx = new FileSystemXmlApplicationContext(this.cfgFile);
				}catch( Throwable ex ){
					LOGGER.error( "loadObjects error", ex );
					return false;
				}
			}
			return true;
		}

		@Override
		public Object getObject(String name) {

			if( ctx.containsBean( name ) ){
				return ctx.getBean( name );
			}else{
				return null;
			}

		}

		@Override
		public <T> T getObject(Class<T> requiredType) {

			return ctx.getBean( requiredType );

		}


	}


}
